﻿Imports System
Imports System.CodeDom
Imports System.Collections.Generic
Imports System.Diagnostics.CodeAnalysis
Imports System.Globalization
Imports System.Reflection
Imports System.Text
Imports System.Workflow.ComponentModel.Compiler

Namespace System.Workflow.Activities.Rules
    Friend Class IndexerPropertyExpression
        Inherits RuleExpressionInternal
        ' Methods
        Friend Overrides Sub AnalyzeUsage(ByVal expression As CodeExpression, ByVal analysis As RuleAnalysis, ByVal isRead As Boolean, ByVal isWritten As Boolean, ByVal qualifier As RulePathQualifier)
            Dim expression2 As CodeIndexerExpression = DirectCast(expression, CodeIndexerExpression)
            Dim targetObject As CodeExpression = expression2.TargetObject
            If (analysis.Validation.ExpressionInfo(targetObject) Is Nothing) Then
                Dim exception As New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated, New Object(0  - 1) {}))
                exception.Data.Item("ErrorObject") = targetObject
                Throw exception
            End If
            Dim info2 As RulePropertyExpressionInfo = [TryCast](analysis.Validation.ExpressionInfo(expression2),RulePropertyExpressionInfo)
            If (info2 Is Nothing) Then
                Dim exception2 As New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated, New Object(0  - 1) {}))
                exception2.Data.Item("ErrorObject") = expression2
                Throw exception2
            End If
            Dim propertyInfo As PropertyInfo = info2.PropertyInfo
            Dim attributedExprs As New List([Of] CodeExpression)
            analysis.AnalyzeRuleAttributes(propertyInfo, targetObject, qualifier, expression2.Indices, propertyInfo.GetIndexParameters, attributedExprs)
            If Not attributedExprs.Contains(targetObject) Then
                RuleExpressionWalker.AnalyzeUsage(analysis, targetObject, isRead, isWritten, qualifier)
            End If
            Dim i As Integer
            For i = 0 To expression2.Indices.Count - 1
                Dim item As CodeExpression = expression2.Indices.Item(i)
                If Not attributedExprs.Contains(item) Then
                    RuleExpressionWalker.AnalyzeUsage(analysis, item, True, False, Nothing)
                End If
            Next i
        End Sub

        Friend Overrides Function Clone(ByVal expression As CodeExpression) As CodeExpression
            Dim expression2 As CodeIndexerExpression = DirectCast(expression, CodeIndexerExpression)
            Dim targetObject As CodeExpression = RuleExpressionWalker.Clone(expression2.TargetObject)
            Dim indices As CodeExpression() = New CodeExpression(expression2.Indices.Count  - 1) {}
            Dim i As Integer
            For i = 0 To indices.Length - 1
                indices(i) = RuleExpressionWalker.Clone(expression2.Indices.Item(i))
            Next i
            Return New CodeIndexerExpression(targetObject, indices)
        End Function

        Friend Overrides Sub Decompile(ByVal expression As CodeExpression, ByVal stringBuilder As StringBuilder, ByVal parentExpression As CodeExpression)
            Dim expression2 As CodeIndexerExpression = DirectCast(expression, CodeIndexerExpression)
            Dim targetObject As CodeExpression = expression2.TargetObject
            If (targetObject Is Nothing) Then
                Dim exception As New RuleEvaluationException(String.Format(CultureInfo.CurrentCulture, Messages.NullIndexerTarget, New Object(0  - 1) {}))
                exception.Data.Item("ErrorObject") = expression2
                Throw exception
            End If
            If ((expression2.Indices Is Nothing) OrElse (expression2.Indices.Count = 0)) Then
                Dim exception2 As New RuleEvaluationException(String.Format(CultureInfo.CurrentCulture, Messages.MissingIndexExpressions, New Object(0  - 1) {}))
                exception2.Data.Item("ErrorObject") = expression2
                Throw exception2
            End If
            RuleExpressionWalker.Decompile(stringBuilder, targetObject, expression2)
            stringBuilder.Append("["c)
            RuleExpressionWalker.Decompile(stringBuilder, expression2.Indices.Item(0), Nothing)
            Dim i As Integer
            For i = 1 To expression2.Indices.Count - 1
                stringBuilder.Append(", ")
                RuleExpressionWalker.Decompile(stringBuilder, expression2.Indices.Item(i), Nothing)
            Next i
            stringBuilder.Append("]"c)
        End Sub

        Friend Overrides Function Evaluate(ByVal expression As CodeExpression, ByVal execution As RuleExecution) As RuleExpressionResult
            Dim expression2 As CodeIndexerExpression = DirectCast(expression, CodeIndexerExpression)
            Dim info As RulePropertyExpressionInfo = [TryCast](execution.Validation.ExpressionInfo(expression2),RulePropertyExpressionInfo)
            If (info Is Nothing) Then
                Dim exception As New InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated, New Object(0  - 1) {}))
                exception.Data.Item("ErrorObject") = expression2
                Throw exception
            End If
            Dim propertyInfo As PropertyInfo = info.PropertyInfo
            Dim targetObject As Object = RuleExpressionWalker.Evaluate(execution, expression2.TargetObject).Value
            If (targetObject Is Nothing) Then
                Dim exception2 As New RuleEvaluationException(String.Format(CultureInfo.CurrentCulture, Messages.TargetEvaluatedNullIndexer, New Object(0  - 1) {}))
                exception2.Data.Item("ErrorObject") = expression2
                Throw exception2
            End If
            Dim count As Integer = expression2.Indices.Count
            Dim indexParameters As ParameterInfo() = propertyInfo.GetIndexParameters
            Dim indexerArguments As Object() = New Object(indexParameters.Length  - 1) {}
            Dim length As Integer = indexParameters.Length
            If info.NeedsParamsExpansion Then
                length -= 1
            End If
            Dim index As Integer = 0
            Do While (index < length)
                Dim expressionType As Type = execution.Validation.ExpressionInfo(expression2.Indices.Item(index)).ExpressionType
                Dim result As RuleExpressionResult = RuleExpressionWalker.Evaluate(execution, expression2.Indices.Item(index))
                indexerArguments(index) = Executor.AdjustType(expressionType, result.Value, indexParameters(index).ParameterType)
                index += 1
            Loop
            If (length < count) Then
                Dim info3 As ParameterInfo = indexParameters(length)
                Dim parameterType As Type = info3.ParameterType
                Dim elementType As Type = parameterType.GetElementType
                Dim array As Array = DirectCast(parameterType.InvokeMember(parameterType.Name, BindingFlags.CreateInstance, Nothing, Nothing, New Object() { (count - index) }, CultureInfo.CurrentCulture), Array)
                Do While (index < count)
                    Dim operandType As Type = execution.Validation.ExpressionInfo(expression2.Indices.Item(index)).ExpressionType
                    Dim result2 As RuleExpressionResult = RuleExpressionWalker.Evaluate(execution, expression2.Indices.Item(index))
                    array.SetValue(Executor.AdjustType(operandType, result2.Value, elementType), CInt((index - length)))
                    index += 1
                Loop
                indexerArguments(length) = array
            End If
            Return New RulePropertyResult(propertyInfo, targetObject, indexerArguments)
        End Function

        Friend Overrides Function Match(ByVal expression As CodeExpression, ByVal comperand As CodeExpression) As Boolean
            Dim expression2 As CodeIndexerExpression = DirectCast(expression, CodeIndexerExpression)
            Dim expression3 As CodeIndexerExpression = DirectCast(comperand, CodeIndexerExpression)
            If Not RuleExpressionWalker.Match(expression2.TargetObject, expression3.TargetObject) Then
                Return False
            End If
            If (expression2.Indices.Count <> expression3.Indices.Count) Then
                Return False
            End If
            Dim i As Integer
            For i = 0 To expression2.Indices.Count - 1
                If Not RuleExpressionWalker.Match(expression2.Indices.Item(i), expression3.Indices.Item(i)) Then
                    Return False
                End If
            Next i
            Return True
        End Function

        <SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")> _
        Friend Overrides Function Validate(ByVal expression As CodeExpression, ByVal validation As RuleValidation, ByVal isWritten As Boolean) As RuleExpressionInfo
            Dim item As ValidationError = Nothing
            Dim info As RulePropertyExpressionInfo = Nothing
            Dim nonPublic As Boolean = False
            Dim expressionType As Type = Nothing
            Dim newParent As CodeIndexerExpression = DirectCast(expression, CodeIndexerExpression)
            Dim targetObject As CodeExpression = newParent.TargetObject
            If (targetObject Is Nothing) Then
                item = New ValidationError(Messages.NullIndexerTarget, &H53D)
                item.UserData.Item("ErrorObject") = newParent
                validation.Errors.Add(item)
                Return Nothing
            End If
            If TypeOf targetObject Is CodeTypeReferenceExpression Then
                item = New ValidationError(Messages.IndexersCannotBeStatic, &H53D)
                item.UserData.Item("ErrorObject") = newParent
                validation.Errors.Add(item)
                Return Nothing
            End If
            If ((newParent.Indices Is Nothing) OrElse (newParent.Indices.Count = 0)) Then
                item = New ValidationError(Messages.MissingIndexExpressions, &H53D)
                item.UserData.Item("ErrorObject") = newParent
                validation.Errors.Add(item)
                Return Nothing
            End If
            Try 
                If Not validation.PushParentExpression(newParent) Then
                    Return Nothing
                End If
                Dim info2 As RuleExpressionInfo = RuleExpressionWalker.Validate(validation, newParent.TargetObject, False)
                If (info2 Is Nothing) Then
                    Return Nothing
                End If
                expressionType = info2.ExpressionType
                If (expressionType Is Nothing) Then
                    Return Nothing
                End If
                If (expressionType Is GetType(NullLiteral)) Then
                    item = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.NullIndexerTarget, New Object(0  - 1) {}), &H53D)
                    item.UserData.Item("ErrorObject") = newParent
                    validation.Errors.Add(item)
                    expressionType = Nothing
                End If
                Dim argumentExprs As New List([Of] CodeExpression)
                Dim flag2 As Boolean = False
                Dim i As Integer
                For i = 0 To newParent.Indices.Count - 1
                    Dim expression4 As CodeExpression = newParent.Indices.Item(i)
                    If (expression4 Is Nothing) Then
                        item = New ValidationError(Messages.NullIndexExpression, &H53D)
                        item.UserData.Item("ErrorObject") = newParent
                        validation.Errors.Add(item)
                        flag2 = True
                    Else
                        Dim expression5 As CodeDirectionExpression = [TryCast](expression4,CodeDirectionExpression)
                        If ((Not expression5 Is Nothing) AndAlso (expression5.Direction <> FieldDirection.In)) Then
                            item = New ValidationError(Messages.IndexerArgCannotBeRefOrOut, &H19D)
                            item.UserData.Item("ErrorObject") = newParent
                            validation.Errors.Add(item)
                            flag2 = True
                        End If
                        If TypeOf expression4 Is CodeTypeReferenceExpression Then
                            item = New ValidationError(String.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, New Object() { expression4.GetType.FullName }), &H548)
                            item.UserData.Item("ErrorObject") = expression4
                            validation.AddError(item)
                            flag2 = True
                        End If
                        If (RuleExpressionWalker.Validate(validation, expression4, False) Is Nothing) Then
                            flag2 = True
                        Else
                            argumentExprs.Add(expression4)
                        End If
                    End If
                Next i
                If (expressionType Is Nothing) Then
                    Return Nothing
                End If
                If flag2 Then
                    Return Nothing
                End If
                Dim bindingFlags As BindingFlags = (BindingFlags.Public Or BindingFlags.Instance)
                If validation.AllowInternalMembers(expressionType) Then
                    bindingFlags = (bindingFlags Or BindingFlags.NonPublic)
                    nonPublic = True
                End If
                info = validation.ResolveIndexerProperty(expressionType, bindingFlags, argumentExprs, item)
                If (info Is Nothing) Then
                    item.UserData.Item("ErrorObject") = newParent
                    validation.Errors.Add(item)
                    Return Nothing
                End If
            Finally
                validation.PopParentExpression
            End Try
            Dim propertyInfo As PropertyInfo = info.PropertyInfo
            Dim accessorMethod As MethodInfo = If(isWritten, propertyInfo.GetSetMethod(nonPublic), propertyInfo.GetGetMethod(nonPublic))
            If (accessorMethod Is Nothing) Then
                Dim format As String = If(isWritten, Messages.UnknownPropertySet, Messages.UnknownPropertyGet)
                item = New ValidationError(String.Format(CultureInfo.CurrentCulture, format, New Object() { propertyInfo.Name, RuleDecompiler.DecompileType(expressionType) }), &H54A)
                item.UserData.Item("ErrorObject") = newParent
                validation.Errors.Add(item)
                Return Nothing
            End If
            If Not validation.ValidateMemberAccess(targetObject, expressionType, accessorMethod, propertyInfo.Name, newParent) Then
                Return Nothing
            End If
            Dim customAttributes As Object() = propertyInfo.GetCustomAttributes(GetType(RuleAttribute), True)
            If ((Not customAttributes Is Nothing) AndAlso (customAttributes.Length > 0)) Then
                Dim stack As New Stack([Of] MemberInfo)
                stack.Push(propertyInfo)
                Dim flag3 As Boolean = True
                Dim attribute As RuleAttribute
                For Each attribute In customAttributes
                    If Not attribute.Validate(validation, propertyInfo, expressionType, propertyInfo.GetIndexParameters) Then
                        flag3 = False
                    End If
                Next
                stack.Pop
                If Not flag3 Then
                    Return Nothing
                End If
            End If
            Return info
        End Function

    End Class
End Namespace

